package com.cainli.image;

import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.lang.ref.WeakReference;
import java.util.ArrayList;

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.AsyncTask;
import android.os.Handler;
import android.util.DisplayMetrics;
import android.util.Log;

import com.cainli.task.Task;

/**
 * gif图片对象
 * 
 * 
 */
public class GifImage implements Runnable {
	public static final int DENSITY_NONE = 0;

	/**
	 * 全局字段, 标识暂停所有gif的解码
	 */
	private static boolean sPaused = false;

	private RandomAccessFile file;

	// 宽
	private int width;
	// 高
	private int height;
	// 1 : 全局色表标记
	private boolean gctFlag;
	// 局部色表标记
	private boolean lctFlag;
	// 全局色表大小
	private int gctSize;
	// 循环次数,貌似没用
	private int loopCount;

	// 背景色索引
	private int bgIndex;
	// 背景色
	private int bgColor;
	// 像素长宽比（？？？）
	private int pixelAspect;

	// 全局的色表
	private int[] gct;
	// 当前帧色表
	private int[] lct;
	// 使用的色表
	private int[] act;

	protected byte[] block = new byte[256]; // current data block
	private int blockSize;

	// last graphic control extension info
	private int dispose;
	// 透明色
	private boolean transparency;
	// 下一帧的延迟
	private int delay;
	// 透明色的索引
	private int transIndex;

	// 下一帧属性
	private int ix;
	private int iy;
	private int iw;
	private int ih;

	protected static final int MaxStackSize = 4096;

	private boolean interlace;

	private int lctSize;

	// 解图片所用到的数组
	private short[] prefix;
	private byte[] suffix;
	private byte[] pixels;
	private byte[] pixelStack;

	// 当前使用的图片
	private Bitmap image;
	// 下一帧的图片
	private Bitmap nextImage;

	// 上一帧的清除方式
	private int lastDispose;

	private int lastBgColor;

	// 已经循环过的次数
	// private int loopedCount;

	// gif主体的索引
	private long contentIndex;

	/**
	 * 当前帧的延迟
	 */
	private int currentFrameDelay;

	// 上一帧所在位置
	private long lastFramePoint = -1;

	/**
	 * 回调
	 */
	private ArrayList<WeakReference<Callback>> callbacks = new ArrayList<WeakReference<Callback>>();

	// /**
	// * handler
	// */
	private Handler sHandler;

	private boolean mDecodeNextFrameEnd = true;

	private int mTaskType;

	private static final String TAG = "GifImage";

	/**
	 * 缓存消息的容量, 暂定为100
	 */
	private static final int PENDING_ACTION_CAPACITY = 100;

	/**
	 * 暂停恢复后, 用来还原消息, 有容量限制
	 */
	private static final ArrayList<WeakReference<GifImage>> sPendingActions = new ArrayList<WeakReference<GifImage>>(
			PENDING_ACTION_CAPACITY + 5) {

		public boolean add(WeakReference<GifImage> object) {
			// GifImage gif = object.get();
			Log.d(TAG, "addAction");
			boolean ret = super.add(object);
			ensureCapacity();
			return ret;
		};

		private void ensureCapacity() {
			int size = size();
			if (size > PENDING_ACTION_CAPACITY) {
				removeRange(0, size - PENDING_ACTION_CAPACITY - 1);
			}
		}
	};

	/**
	 * 
	 * @param f
	 * @param taskType
	 * @throws IOException
	 */
	public GifImage(File f, int taskType) throws IOException {
		try {
			this.file = new RandomAccessFile(f, "r");
			this.mTaskType = taskType;
			// 读取header、Logical Screen Descriptor和全局色表
			readHeader();
		} catch (IOException e) {
			if (this.file != null) {
				try {
					this.file.close();
				} catch (Exception e1) {
				}
			}
			throw e;
		}
	}

	private void readHeader() throws IOException {
		byte[] id = new byte[6];
		file.read(id);

		if (id[0] == (byte) 'G' && id[1] == (byte) 'I' && id[2] == (byte) 'F') {
			// 读取宽,高,背景色索引,是否含有全局色表等信息
			readLSD();
			// 读取全局色表
			if (gctFlag) {
				gct = readColorTable(gctSize);
				bgColor = gct[bgIndex];
			}
			// 第一帧所在的位置
			contentIndex = file.getFilePointer();
		}
		// 非GIF文件,抛异常
		else {
			throw new IOException("the file is not gif file");
		}
	}

	/**
	 * Reads color table as 256 RGB integer values 读全局色表
	 * 
	 * @param ncolors
	 *            int number of colors to read
	 * @return int array containing 256 colors (packed ARGB with full alpha)
	 * @throws IOException
	 */
	protected int[] readColorTable(int ncolors) throws IOException {
		int nbytes = 3 * ncolors;
		int[] tab = null;
		byte[] c = new byte[nbytes];
		int n = 0;
		n = file.read(c);

		if (n < nbytes) {
			throw new IOException("decode gif failed");
		} else {
			tab = new int[256]; // max size to avoid bounds checks
			int i = 0;
			int j = 0;
			while (i < ncolors) {
				int r = ((int) c[j++]) & 0xff;
				int g = ((int) c[j++]) & 0xff;
				int b = ((int) c[j++]) & 0xff;
				tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b;
			}
		}
		return tab;
	}

	/**
	 * Reads Logical Screen Descriptor
	 * 
	 * @throws IOException
	 */
	protected void readLSD() throws IOException {

		// logical screen size
		width = readShort();
		height = readShort();

		// packed fields
		int packed = file.read();
		gctFlag = (packed & 0x80) != 0; // 1 : global color table flag
		// 2-4 : color resolution
		// 5 : gct sort flag
		gctSize = 2 << (packed & 7); // 6-8 : gct size

		bgIndex = file.read(); // background color index
		pixelAspect = file.read(); // pixel aspect ratio
	}

	private int readShort() throws IOException {
		byte[] buffer = new byte[2];
		if (file.read(buffer, 0, buffer.length) != buffer.length) {
			throw new EOFException();
		}
		return ((buffer[1] & 0xff) << 8) + (buffer[0] & 0xff);
	}

	@Override
	protected void finalize() throws Throwable {
		super.finalize();
		file.close();
	}

	/**
	 * Reads next variable length block from input.
	 * 
	 * @return number of bytes stored in "buffer"
	 * @throws IOException
	 */
	protected int readBlock() throws IOException {
		blockSize = file.read();
		int n = 0;
		if (blockSize > 0) {
			try {
				int count = 0;
				while (n < blockSize) {
					count = file.read(block, n, blockSize - n);
					if (count == -1)
						break;
					n += count;
				}
			} catch (IOException e) {
			}

			if (n < blockSize) {
				throw new IOException("block load error");
			}
		}
		return n;
	}

	/**
	 * 读下一帧
	 * 
	 * @return
	 * @throws IOException
	 */
	public synchronized boolean getNextFrame() throws IOException {
		// read GIF file content blocks
		// boolean done = false;
		// Log.d(TAG, "decode next frame");
		// URLDrawableTestApplication.log("decode next frame");
		long position = file.getFilePointer();
		int loop = 0;
		while (loop < 10000) {
			int code = file.read();
			switch (code) {
			// 图片
			case 0x2C: // image separator
				// 读取图片, 基于LZW算法.
				readImage();
				lastFramePoint = position;
				return true;
				// 几乎没有
			case 0x21: // extension
				code = file.read();
				switch (code) {
				case 0xf9: // graphics control extension
					readGraphicControlExt();
					break;

				case 0xff: // application extension
					readBlock();
					String app = "";
					for (int i = 0; i < 11; i++) {
						app += (char) block[i];
					}
					if (app.equals("NETSCAPE2.0")) {
						readNetscapeExt();
					} else
						skip(); // don't care
					break;

				default: // uninteresting extension
					skip();
				}
				break;

			case 0x3b: // 终止
				// done = true;
				// 回第一帧
				// if (loopCount == 0 || loopedCount < loopCount)
				// {
				// loopedCount++;
				// 只有一帧的判断
				if (contentIndex == lastFramePoint) {
					return false;
				}
				// 回第一帧,重新解码
				resetFrame();
				file.seek(contentIndex);
				lastDispose = 2;
				// }
				break;

			case 0x00: // bad byte, but keep going and see what happens
				break;

			default:
				throw new IOException("gif decode error");
			}
			loop++;
		}
		return false;
	}

	private void readImage() throws IOException {
		int tix = readShort(); // (sub)image position & size
		int tiy = readShort();
		int tiw = readShort();
		int tih = readShort();

		int packed = file.read();
		lctFlag = (packed & 0x80) != 0; // 1 - local color table flag
		interlace = (packed & 0x40) != 0; // 2 - interlace flag
		// 3 - sort flag
		// 4-5 - reserved
		lctSize = 2 << (packed & 7); // 6-8 - local color table size

		if (lctFlag) {
			lct = readColorTable(lctSize); // read table
			act = lct; // make local table active
		} else {
			act = gct; // make global table active
			if (bgIndex == transIndex)
				bgColor = 0;
		}
		int save = 0;
		if (transparency) {
			save = act[transIndex];
			act[transIndex] = 0; // set transparent color if specified
		}

		if (act == null) {
			throw new IOException("Gif decode error"); // no color table defined
		}

		decodeImageData(tiw, tih); // decode pixel data
		skip();

		// frameCount++;

		updateImage(tix, tiy, tiw, tih);

		ix = tix;
		iy = tiy;
		iw = tiw;
		ih = tih;

		if (transparency) {
			act[transIndex] = save;
		}
		resetFrame();

	}

	private void resetFrame() {
		lastDispose = dispose;
		// lastImage = image;
		lastBgColor = bgColor;
	}

	/**
	 * 更新下一帧
	 * 
	 * @param tih
	 * @param tiw
	 * @param tiy
	 * @param tix
	 */
	private void updateImage(int tix, int tiy, int tiw, int tih) {
		if (lastDispose > 0) {
			// 恢复到背景
			if (lastDispose == 2) {
				if (image == null || (iw == width && ih == height)) {
					nextImage = createEmptyBitmap();
				} else {
					nextImage = Bitmap.createBitmap(image);
					// 擦掉当前帧所在位置的像素
					int[] pixes = new int[iw * ih];
					if (lastBgColor != 0) {
						for (int i = 0; i < pixes.length; i++) {
							pixes[i] = lastBgColor;
						}
					}
					nextImage.setPixels(pixes, 0, iw, ix, iy, iw, ih);
				}
			}
			// 恢复到上一帧
			else if (lastDispose == 3) {
				// 情况很少，而且比较占内存
			}
		}

		// 创建下一帧的缓存
		if (nextImage == null) {
			if (image == null) {
				nextImage = createEmptyBitmap();
			} else {
				nextImage = Bitmap.createBitmap(image);
			}
		}

		// 画进Bitmap
		int[] pixelRgb = getRgbPixels(pixels, tiw, tih);
		Canvas c = new Canvas(nextImage);
		// 把像素颜色信息画进nextImage中
		c.drawBitmap(pixelRgb, 0, tiw, tix, tiy, tiw, tih, true, null);
	}

	private Bitmap createEmptyBitmap() {
		Bitmap b = Bitmap.createBitmap(width, height, Config.ARGB_4444);
		// b.setDensity(160);
		if (!transparency) {
			b.eraseColor(lastBgColor);
		}
		return b;
	}

	/**
	 * 将下一帧数据应用
	 */
	public synchronized void applyNextFrame() {
		image = nextImage;
		currentFrameDelay = delay;
	}

	private int[] getRgbPixels(byte[] pixelIndices, int tiw, int tih) {
		int[] pixelrgb = new int[pixelIndices.length];
		if (!interlace) {
			for (int i = 0; i < pixelrgb.length; i++) {
				int index = ((int) pixelIndices[i]) & 0xff;
				pixelrgb[i] = act[index];
			}
			return pixelrgb;
		} else {
			// copy each source line to the appropriate place in the destination
			int pass = 1;
			int inc = 8;
			int iline = 0;
			for (int i = 0; i < tih; i++) {
				int line = i;
				if (interlace) {
					if (iline >= tih) {
						pass++;
						switch (pass) {
						case 2:
							iline = 4;
							break;
						case 3:
							iline = 2;
							inc = 4;
							break;
						case 4:
							iline = 1;
							inc = 2;
						}
					}
					line = iline;
					iline += inc;
				}
				// line += tiy;
				// 计算一行的像素值
				if (line < tih) {
					int dx = line * tiw;// start of line in dest
					// int dx = k;
					int dlim = dx + tiw; // end of dest line
					if ((dx + tiw) < dlim) {
						dlim = dx + tiw; // past dest edge
					}
					int sx = i * tiw; // start of line in source
					while (dx < dlim) {
						// map color and insert in destination
						int index = ((int) pixels[sx++]) & 0xff;
						int c = act[index];
						if (c != 0) {
							pixelrgb[dx] = c;
						}
						dx++;
					}
				}
			}
			return pixelrgb;
		}
	}

	/**
	 * Decodes LZW image data into pixel array. Adapted from John Cristy's
	 * ImageMagick. 解码数据，用的是lzw压缩算法
	 * 
	 * @param tih
	 * @param tiw
	 * @throws IOException
	 */
	protected void decodeImageData(int tiw, int tih) throws IOException {
		int NullCode = -1;
		int npix = tiw * tih;
		int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, data_size, first, top, bi, pi;

		if ((pixels == null) || (pixels.length < npix)) {
			pixels = new byte[npix]; // allocate new pixel array
		}
		if (prefix == null)
			prefix = new short[MaxStackSize];
		if (suffix == null)
			suffix = new byte[MaxStackSize];
		if (pixelStack == null)
			pixelStack = new byte[MaxStackSize + 1];

		// Initialize GIF data stream decoder.

		data_size = file.read();
		clear = 1 << data_size;
		end_of_information = clear + 1;
		available = clear + 2;
		old_code = NullCode;
		code_size = data_size + 1;
		code_mask = (1 << code_size) - 1;
		for (code = 0; code < clear; code++) {
			prefix[code] = 0;
			suffix[code] = (byte) code;
		}

		// Decode GIF pixel stream.

		datum = bits = count = first = top = pi = bi = 0;

		for (i = 0; i < npix;) {
			if (top == 0) {
				if (bits < code_size) {
					// Load bytes until there are enough bits for a code.
					if (count == 0) {
						// Read a new data block.
						count = readBlock();
						if (count <= 0)
							break;
						bi = 0;
					}
					datum += (((int) block[bi]) & 0xff) << bits;
					bits += 8;
					bi++;
					count--;
					continue;
				}

				// Get the next code.

				code = datum & code_mask;
				datum >>= code_size;
				bits -= code_size;

				// Interpret the code

				if ((code > available) || (code == end_of_information))
					break;
				if (code == clear) {
					// Reset decoder.
					code_size = data_size + 1;
					code_mask = (1 << code_size) - 1;
					available = clear + 2;
					old_code = NullCode;
					continue;
				}
				if (old_code == NullCode) {
					pixelStack[top++] = suffix[code];
					old_code = code;
					first = code;
					continue;
				}
				in_code = code;
				if (code == available) {
					pixelStack[top++] = (byte) first;
					code = old_code;
				}
				while (code > clear) {
					pixelStack[top++] = suffix[code];
					code = prefix[code];
				}
				first = ((int) suffix[code]) & 0xff;

				// Add a new string to the string table,

				if (available >= MaxStackSize)
					break;
				pixelStack[top++] = (byte) first;
				prefix[available] = (short) old_code;
				suffix[available] = (byte) first;
				available++;
				if (((available & code_mask) == 0)
						&& (available < MaxStackSize)) {
					code_size++;
					code_mask += available;
				}
				old_code = in_code;
			}

			// Pop a pixel off the pixel stack.

			top--;
			pixels[pi++] = pixelStack[top];
			i++;
		}

		for (i = pi; i < npix; i++) {
			pixels[i] = 0; // clear missing pixels
		}

	}

	// 绘制当前帧
	public void draw(Canvas canvas, Rect r, Paint paint) {
		// draw一定在ui线程调用
		if (sHandler == null) {
			sHandler = new Handler();
		}
		// 绘制当前帧.第一次调用为空.因此第一帧是空的.
		if (image != null) {
			canvas.drawBitmap(image, null, r, paint);
		}
		// 使用task.在另一个线程里去解下一帧
		if (mDecodeNextFrameEnd) {
			// mTask = new DecodeNextFrameTask(this, getDelay());
			// mTask.execute();
			if (!sPaused) {
				executeNewTask();
			} else {
				sPendingActions.add(new WeakReference<GifImage>(this));
				// 阻止重复绘制
				mDecodeNextFrameEnd = false;
			}
		}
	}

	private void executeNewTask() {
		mDecodeNextFrameEnd = false;
		// 下一帧的时间
		long nextFrameTime = android.os.SystemClock.uptimeMillis() + getDelay();
		if (mTaskType == URLDrawableParams.TASK_TYPE_SWING_WORKER) {
			new DecodeNextFrameTask(nextFrameTime).execute();
		} else {
			new DecodeNextFrameAsyncTask(nextFrameTime).execute((Void) null);
		}
	}

	public Bitmap getCurrentFrame() {
		return image;
	}

	/**
	 * 获取当前帧后一帧的延迟
	 * 
	 * @return 后一帧的延迟
	 */
	public int getDelay() {
		return currentFrameDelay < 100 ? 100 : currentFrameDelay;
	}

	/**
	 * Reads Netscape extenstion to obtain iteration count
	 * 
	 * @throws IOException
	 */
	protected void readNetscapeExt() throws IOException {
		do {
			readBlock();
			if (block[0] == 1) {
				// loop count sub-block
				int b1 = ((int) block[1]) & 0xff;
				int b2 = ((int) block[2]) & 0xff;
				loopCount = (b2 << 8) | b1;
			}
		} while ((blockSize > 0));
	}

	/**
	 * Reads Graphics Control Extension values
	 * 
	 * @throws IOException
	 */
	protected void readGraphicControlExt() throws IOException {
		file.read(); // block size
		int packed = file.read(); // packed fields
		dispose = (packed & 0x1c) >> 2; // disposal method
		if (dispose == 0) {
			dispose = 1; // elect to keep old image if discretionary
		}
		transparency = (packed & 1) != 0;
		delay = readShort() * 10; // delay in milliseconds
		transIndex = file.read(); // transparent color index
		file.read(); // block terminator
	}

	protected void skip() throws IOException {
		do {
			readBlock();
		} while (blockSize > 0);
	}

	public int getWidth() {
		return width;
	}

	/**
	 * 获取基于density的宽度
	 * 
	 * @param targetDensity
	 * @return
	 */
	public int getScaledWidth(int targetDensity) {
		return scaleFromDensity(width, DisplayMetrics.DENSITY_DEFAULT,
				targetDensity);
	}

	public int getHeight() {
		return height;
	}

	/**
	 * 获取基于density的高度
	 * 
	 * @param targetDensity
	 * @return
	 */
	public int getScaledHeight(int targetDensity) {
		return scaleFromDensity(height, DisplayMetrics.DENSITY_DEFAULT,
				targetDensity);
	}

	static public int scaleFromDensity(int size, int sdensity, int tdensity) {
		if (sdensity == DENSITY_NONE || sdensity == tdensity) {
			return size;
		}

		// Scale by tdensity / sdensity, rounding up.
		return ((size * tdensity) + (sdensity >> 1)) / sdensity;
	}

	public void addCallBack(Callback callback) {
		if (callback != null) {
			callbacks.add(new WeakReference<Callback>(callback));
		}
	}

	public void removeCallBack(Callback callback) {
		for (int i = 0; i < callbacks.size(); i++) {
			WeakReference<Callback> reference = callbacks.get(i);
			// 如果为空，移掉
			if (reference == null || reference.get() == null) {
				callbacks.remove(i--);
			}
			// 如果找到，移掉
			else if (reference.get() == callback) {
				callbacks.remove(i--);
				return;
			}
		}
	}

	/**
	 * 重绘,在ui线程执行
	 */
	private void invalidateSelf() {
		for (int i = 0; i < callbacks.size(); i++) {
			// QLog.d("GifImage", "invalidateSelf");
			WeakReference<Callback> reference = callbacks.get(i);
			if (reference == null || reference.get() == null) {
				callbacks.remove(i--);
			} else {
				reference.get().invalidateSelf();
			}
		}
	}

	/**
	 * 重绘,在ui线程执行
	 */
	private void scheduleSelf(Runnable what, long when) {
		for (int i = 0; i < callbacks.size(); i++) {
			// QLog.d("GifImage", "invalidateSelf");
			WeakReference<Callback> reference = callbacks.get(i);
			if (reference == null || reference.get() == null) {
				callbacks.remove(i--);
			} else {
				reference.get().scheduleSelf(what, when);
			}
		}
	}

	public interface Callback {
		public void invalidateSelf();

		public void scheduleSelf(Runnable what, long when);
	}

	@Override
	public void run() {
		// 通知重绘
		applyNextFrame();
		if (sPaused) {
			sPendingActions.add(new WeakReference<GifImage>(this));
			// 理论上不需要这一句
			mDecodeNextFrameEnd = false;
		} else {
			// 重绘
			invalidateSelf();
			mDecodeNextFrameEnd = true;
		}
	}

	private void reDraw() {
		// 重绘
		invalidateSelf();
		mDecodeNextFrameEnd = true;
	}

	private void onDecodeNextFrameSuccessed(boolean hasNextFrame,
			long nextFrameDrawingTime) {
		// 返回false只有两种情况,gif只有1帧或者出错...
		if (hasNextFrame) {
			long now = android.os.SystemClock.uptimeMillis();
			// QLog.d("Gif", "now:" + now + " next:" + nextFrameDrawingTime);
			if (now < nextFrameDrawingTime) {
				sHandler.postDelayed(this, nextFrameDrawingTime - now);
			}
			// 如果当前时间已经超过了下一帧的时间
			// 立刻通知重绘
			else {
				// run();
				sHandler.post(this);
			}
		} else {
			// 无视
		}
	}

	private void onDecodeNextFrameFailed(Throwable e) {
		Log.e(TAG, "gif decode error. " + file, e);
		mDecodeNextFrameEnd = true;
	}

	private void onDecodeNextFrameCanceled() {
		Log.e(TAG, "gif decode canceled. " + file);
		mDecodeNextFrameEnd = true;
	}

	// private Object mTask;

	/**
	 * 判断是否需要解成动态gif,基于内存因素考虑，条件为，宽高均小于200像素，并且gif帧数大于1帧
	 * 
	 * @param f
	 *            要解码的文件
	 * @return 是否需要解成动态gif
	 */
	public static boolean needDecodeAnimation(File f) {
		RandomAccessFile rf = null;
		try {
			rf = new RandomAccessFile(f, "r");
			// 先读6个字节
			byte[] tmp = new byte[10];
			rf.read(tmp);
			// 不是gif文件
			if (tmp[0] != (byte) 'G' || tmp[1] != (byte) 'I'
					|| tmp[2] != (byte) 'F') {
				return false;
			}
			int width = ((tmp[7] & 0xff) << 8) + (tmp[6] & 0xff);
			int height = ((tmp[9] & 0xff) << 8) + (tmp[8] & 0xff);
			rf.close();
			// 小于4万像素
			if (width * height > 40000) {
				return false;
			}
			// 帧数太难判断了
			return true;

			// int packed = rf.read();
			//
			// boolean gctFlag = (packed & 0x80) != 0;
			// int gctSize = 2 << (packed & 7); // 6-8 : gct size
			// rf.skipBytes(2);
			// // 跳过gct
			// if(gctFlag)
			// {
			// rf.skipBytes(gctSize*3);
			// }
			//
			// int frameCount = 0;
			//
			// int loop = 0;
			// while (loop < 10000)
			// {
			// int code = rf.read();
			// switch (code)
			// {
			//
			// case 0x2C: // image separator
			// frameCount++;
			// skipImage(rf);
			// break;
			//
			// case 0x21: // extension
			// skip(rf);
			// break;
			//
			// case 0x3b: // terminator
			// // 到结束还没return的话，证明少于1帧
			// return false;
			//
			// case 0x00: // bad byte, but keep going and see what happens
			// break;
			//
			// default:
			// throw new IOException("gif decode error");
			// }
			// loop++;
			// }
			//
			//
			// return false;
		} catch (Exception e) {
			return false;
		} finally {
			if (rf != null) {
				try {
					rf.close();
				} catch (IOException e) {
					// do nothing..
				}
			}
		}
	}

	class DecodeNextFrameAsyncTask extends AsyncTask<Void, Void, Object> {
		// 画下一帧的时间
		long nextFrameDrawingTime;

		public DecodeNextFrameAsyncTask(long next) {
			this.nextFrameDrawingTime = next;
		}

		@Override
		protected Object doInBackground(Void... params) {
			// 解下一帧
			try {
				boolean res = getNextFrame();
				// 省一次handle调用
				onDecodeNextFrameSuccessed(res, nextFrameDrawingTime);
				return null;
			} catch (Throwable e) {
				return e;
			}
		}

		@Override
		protected void onPostExecute(Object result) {
			if (result instanceof Throwable) {
				onDecodeNextFrameFailed((Throwable) result);
			}
			// else
			// {
			// onDecodeNextFrameSuccessed((Boolean) result,
			// nextFrameDrawingTime);
			// }
		}

		@Override
		protected void onCancelled() {
			onDecodeNextFrameCanceled();
		}
	}

	class DecodeNextFrameTask extends Task<Boolean, Void> {
		// GifImage image;
		// 画下一帧的时间
		long nextFrameDrawingTime;

		public DecodeNextFrameTask(long next) {
			super(null);
			// 计算出下一帧所绘制的时间
			this.nextFrameDrawingTime = next;
		}

		@Override
		protected Boolean doInBackground() throws Exception {
			// 解下一帧
			try {
				boolean res = getNextFrame();
				// 省一次handle调用
				onDecodeNextFrameSuccessed(res, nextFrameDrawingTime);
				return res;
			} catch (OutOfMemoryError e) {
				throw new Exception(e);
			}
		}

		@Override
		protected void succeeded(Boolean hasNextFrame) {
			// onDecodeNextFrameSuccessed(hasNextFrame, nextFrameDrawingTime);
		}

		@Override
		protected void interrupted(InterruptedException e) {
			onDecodeNextFrameFailed(e);
		}

		@Override
		protected void cancelled() {
			onDecodeNextFrameCanceled();
		}

		@Override
		protected void failed(Throwable cause) {
			onDecodeNextFrameFailed(cause);
		}
	}

	/**
	 * 暂停所有的gif动画, 在系统被终止(Activity stop, 系统休眠等)时调用, 节省开销
	 */
	public static final void pauseAll() {
		sPaused = true;
	}

	/**
	 * 恢复动画, 需要在onDraw之前调用
	 */
	public static final void resumeAll() {

		sPaused = false;
		// sPauseLock.notifyAll();
		// 逆序迭代, 通知重绘
		for (int i = sPendingActions.size() - 1; i >= 0; i--) {
			GifImage drawable = sPendingActions.get(i).get();
			if (drawable != null) {
				drawable.reDraw();
			}
		}
		sPendingActions.clear();
	}
}